#include "GameAi.h"
#include "Team.h"
#include "TeamManager.h"
#include "PeopleManager.h"
#include "League.h"
#include "People.h"
#include "PeopleFunctors.h"
#include "ServiceProvider.h"
#include "Utilities.h"
#include "RandomSystem.h"

#include "StlWrapper.h"

#include <cassert>
#include <algorithm> // only for random_shuffle

GameAI::GameAI(ServiceProvider* const i_sp)
	:m_sp(i_sp)
{
	assert(m_sp);
}

void GameAI::AssignPlayersOnTeams(LeagueVec& o_league) const
{
	typedef int														KeyType;
	typedef STL::multimap<KeyType, Team*, STL::greater<KeyType> >	TeamsScore;
	typedef TeamsScore::iterator									TeamsScoreIterator;
	typedef TeamsScore::reverse_iterator							TeamsScoreRIterator;
	typedef STL::pair<KeyType, Team*>								TeamPair;

	// initing teams with scores

	TeamsScore teams,t_teams;

	for (size_t i = 0; i < o_league.size(); ++i)
	{
		const TeamVec& team = o_league[i]->GetTeams();
		TeamVecCit end = team.end();
		TeamVecCit it = team.begin();
		const int pro_factor = o_league[i]->GetLayerIndex();
		for(it; it != end; ++it)
		{
			KeyType strenght = (pro_factor * -20) + (Rand()%50);
			TeamPair insertion(strenght, *it);
			teams.insert(insertion);
		}
	}
	t_teams = teams;

	// creating player buffer for teams

	int maxPlayer = Team::GetParams().STARTING_TEAM_PLAYERS * teams.size();
	PeopleVec players;
	players.reserve(maxPlayer);

	PeopleManager& memberMgr = m_sp->GetPeopleMgr();
	for(int i = 0; i < maxPlayer; ++i)
		players.push_back(memberMgr.GetNewPeople(true));

	Utilities::Sort(players, PeopleComparisonAveragePlayerSkills);

	// creating trainer buffer for teams

	int maxTrainer =  Team::GetParams().STARTING_TEAM_TRAINERS * t_teams.size();
	PeopleVec trainers;
	trainers.reserve(maxTrainer);

	for(int i = 0; i < maxTrainer; ++i)
		trainers.push_back(memberMgr.GetNewPeople(false));

	Utilities::Sort(trainers, PeopleComparisonAverageTrainerSkills);

	// teams choose players according to team score and players skills

	for(PeopleVecIt playersIt = players.begin(); playersIt != players.end() && !teams.empty(); ++playersIt)
	{
		TeamsScoreIterator rIt = teams.begin();
		TeamPair candidate = *rIt;
		teams.erase(rIt);

		candidate.second->AddPeople(*playersIt);

		if(candidate.second->GetPlayersList().size() < Team::GetParams().STARTING_TEAM_PLAYERS)
		{
			candidate.first -= (Rand()%10);
			teams.insert(candidate);
		}
	}

	// teams choose trainers according to team score and trainers skills

	for(PeopleVecIt trainersIt = trainers.begin(); trainersIt != trainers.end() && !t_teams.empty(); ++trainersIt)
	{
		TeamsScoreIterator rIt = t_teams.begin();
		TeamPair candidate = *rIt;
		t_teams.erase(rIt);

		candidate.second->AddPeople(*trainersIt);
	}

	// here each team has filled its rooster, but no guarantee that roles are ok
	int minimumPlayersPerRole[NUM_SKILL_ROLES] = {2, 4, 4};

	for (size_t i = 0; i < o_league.size(); ++i)
	{
		TeamVec& team = o_league[i]->GetTeams();
		TeamVecCit end = team.end();
		TeamVecCit it = team.begin();
		for(it; it != end; ++it)
		{
			Team& theTeam = *(*it);

			PeopleVec thePlayerList = theTeam.GetPlayersList();
			STD::random_shuffle(thePlayerList.begin(), thePlayerList.end());
			size_t currentRole = 0;

			for(int j = 0; j < NUM_SKILL_ROLES; ++j)
			{
				for(int k = 0; k < minimumPlayersPerRole[j]; ++k)
				{
					assert(currentRole < thePlayerList.size());
					m_sp->GetPeopleMgr().ChangePeopleRole(thePlayerList[currentRole], j);
					++currentRole;
				}
			}
		}
	}
}

void GameAI::PreMatchUpdate(const bool i_doNotPrompt) const
{
	const TeamVec& tl = m_sp->GetTeamMgr().GetTeams();

	// Sells
	for(size_t j = 0; j < tl.size(); ++j)
	{
		Team& team = *tl[j];
		if(!team.IsUserControlled())
			team.GetTeamAI().TrySell(i_doNotPrompt);
	}

	// Buy
	for(size_t j = 0; j < tl.size(); ++j)
	{
		Team& team = *tl[j];
		if(!team.IsUserControlled())
			team.GetTeamAI().TryBuy(i_doNotPrompt);
	}

	// Formation
	for(size_t j = 0; j < tl.size(); ++j)
	{
		Team& team = *tl[j];
		if(!team.IsUserControlled())
			team.GetTeamAI().MakeFormation();
		else
			team.GetTeamAI().CheckFormation();
	}

	if(!i_doNotPrompt)
		STD::cout << STD::endl;
}
